import json
from datetime import timezone, timedelta

from django.contrib.auth.decorators import login_required
from django.contrib.auth import update_session_auth_hash
from django.contrib.auth.models import User
from django.contrib.auth.tokens import default_token_generator
from django.core.mail import send_mail
from django.utils.encoding import force_bytes, force_str
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode

from django.conf import settings
from .forms import ProfileForm, UserForm
from .models import Article, Comment, Category, Reply
import markdown
from django.http import JsonResponse, HttpResponse
from django.views.decorators.csrf import csrf_exempt
from django.urls import reverse
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm, PasswordChangeForm, PasswordResetForm, \
    SetPasswordForm
import math

# get 方法获取所有文章并渲染 index.html 模板,返回首页面

from .models import Article
from django.views import View
from django.views.generic import ListView


class IndexView(View):
    def get(self, request, num=1):
        num = int(num)
        articles = Article.objects.all().order_by('-create_time')
        # 创建分页器对象
        page_obj = Paginator(articles, per_page=2)

        try:
            # 获取某一页数据
            page_post = page_obj.page(num)
        except PageNotAnInteger:
            # 如果页码不是整数，返回第一页
            page_post = page_obj.page(1)
        except EmptyPage:
            # 如果页码超出范围，返回最后一页
            page_post = page_obj.page(page_obj.num_pages)

        # 计算分页信息
        has_previous = page_post.has_previous()
        previous_page_number = page_post.previous_page_number() if has_previous else None
        has_next = page_post.has_next()
        next_page_number = page_post.next_page_number() if has_next else None
        # 获取每一页的页码数列表
        begin = num - int(math.ceil(10.0 / 2))
        if begin < 1:
            begin = 1
        end = begin + 9
        if end > page_obj.num_pages:
            end = page_obj.num_pages
        if end < 10:
            begin = 1
        else:
            begin = end - 9
        page_list = range(begin, end + 1)
        # 将分页信息传递到模板
        context = {
            'articles': page_post,
            'has_previous': has_previous,
            'previous_page_number': previous_page_number,
            'has_next': has_next,
            'next_page_number': next_page_number,
            'current_page': num,
            'page_obj': page_obj,
            'page_list': page_list,
        }
        return render(request, 'index.html', context)


# 展示文章详情，包括文章内容和评论列表
# 文章详情，每添加一个文章，首页显示已添加的文章详情
class ArticleDetailView(View):
    def get(self, request, article_id):
        article = get_object_or_404(Article, id=article_id)
        article.views += 1
        article.save()
        comments = Comment.objects.filter(article=article)
        article.body_html = markdown.markdown(article.content,
                                              extensions=['markdown.extensions.extra', 'markdown.extensions.codehilite',
                                                          'markdown.extensions.toc'])

        return render(request, 'article_detail.html', {'article': article, 'comments': comments})


# 处理文章详情和评论的 GET 和 POST 请求。
class CommentView(View):
    # 用get请求获取文章详情和评论列表
    def get(self, request, article_id):
        article = get_object_or_404(Article, pk=article_id)
        comments = Comment.objects.filter(article=article)
        return render(request, 'article_detail.html', {'article': article, 'comments': comments})

    # 用post请求获取评论列表，获取表单数据，保存到数据库中，重定向到文章详情页面
    def post(self, request, article_id):
        article = get_object_or_404(Article, pk=article_id)
        name = request.POST.get('name')
        content = request.POST.get('content')
        email = request.POST.get('email')

        if not name or not email or not content:
            messages.error(request, "请填写所有字段。")
            return redirect('comment', article_id=article_id)

        comment = Comment(name=name, content=content, email=email, article=article)
        comment.save()
        messages.success(request, "评论已成功提交！")
        return redirect('article_detail', article_id=article_id)


# 定义一个getPoseByid视图，根据类别 ID 获取文章列表
class getPoseByid(ListView):
    model = Article
    template_name = 'articlelist.html'
    context_object_name = 'c_articles'

    def get_queryset(self):
        category_id = self.kwargs.get('category_id')
        category = get_object_or_404(Category, id=category_id)
        c_articles = Article.objects.filter(category=category)
        return c_articles


#
#
from django.shortcuts import render

from django.shortcuts import render
from .models import Article


# 根据指定的年月获取文章列表
class getPoseCreated(ListView):
    model = Article
    template_name = 'articlelist.html'
    context_object_name = 'c_articles'

    def get_queryset(self):
        year = self.kwargs.get('year')
        month = self.kwargs.get('month')
        # 使用 Django ORM 进行查询，避免直接使用 SQL
        sql_query = """
                    SELECT * FROM post_article
                    WHERE YEAR(create_time) = %s AND MONTH(create_time) = %s
                    ORDER BY create_time DESC;
                    """
        c_articles = Article.objects.raw(sql_query, [year, month])
        return c_articles


# 根据标签获取文章列表
def getTagArticles(request, tag):
    c_articles = Article.objects.filter(Tag__iexact=tag)

    return render(request, 'articlelist.html', {'c_articles': c_articles, 'tag': tag})


# 获取所有文章列表，用于首页的归档功能
def getPoseCreatedList(request):
    c_articles = Article.objects.all().order_by('-create_time')
    print(c_articles)
    return render(request, 'articlelist.html', {'c_articles': c_articles})


# 处理点赞评论的 POST 请求
@csrf_exempt
def like_comment(request):
    if request.method == 'POST':
        try:
            data = json.loads(request.body)
            comment_id = data.get('comment_id')
            comment = Comment.objects.get(id=comment_id)
            comment.like_count += 1
            comment.save()
            return JsonResponse({'success': True, 'like_count': comment.like_count})
        except Exception as e:
            return JsonResponse({'success': False, 'error': str(e)})
    return JsonResponse({'success': False, 'error': 'Invalid request method'})


def comment_list(request, article_id):
    # 获取特定文章对象
    article = Article.objects.get(id=article_id)

    # 从请求中获取用户选择的排序方式，默认为按时间降序排列
    sort_by = request.GET.get('sort_by', 'time_desc')

    # 获取文章的所有评论
    comments = article.comments.all()

    # 根据用户选择的排序方式进行评论排序
    if sort_by == 'time_desc':
        # 按评论创建时间降序排列
        comments = comments.order_by('-created_at')
    elif sort_by == 'one_day':
        # 仅显示过去一天内的评论，并按时间降序排列
        one_day_ago = timezone.now() - timedelta(days=1)
        comments = comments.filter(created_at__gte=one_day_ago).order_by('-created_at')
    elif sort_by == 'one_week':
        # 仅显示过去一周内的评论，并按时间降序排列
        one_week_ago = timezone.now() - timedelta(weeks=1)
        comments = comments.filter(created_at__gte=one_week_ago).order_by('-created_at')
    elif sort_by == 'author':
        # 按评论者姓名升序排列
        comments = comments.order_by('name')

    # 构建上下文，包含文章、评论和排序方式信息
    context = {
        'article': article,
        'comments': comments,
        'sort_by': sort_by,
    }

    # 渲染页面并返回HttpResponse对象
    return render(request, 'article_detail.html', context)


def reply_comment(request, article_id, comment_id):
    if request.method == 'POST':
        content = request.POST.get('content')
        article = get_object_or_404(Article, id=article_id)
        comment = get_object_or_404(Comment, id=comment_id)
        reply = Reply.objects.create(
            content=content,
            comment=comment,
            article=article,
        )
        return redirect(reverse('article_detail', args=[article_id]))

    return redirect(reverse('article_detail', args=[article_id]))


# 对文章进行增删改查询


from django.http import HttpResponse
# Create your views here.
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from django.db.models import Q


def page_list(request):
    # /post/list/?page_num=1&page_size=2&keyword=python
    # 1. 获取查询字符串中的分页参数和查询关键字参数
    page_num = request.GET.get('page_num', 1)
    page_size = request.GET.get('page_size', 2)
    keyword = request.GET.get('keyword', '')

    # 2. 把文章中标题或内容包含关键字 keyword 的文章查出来
    page_all = Article.objects.filter(
        Q(title__contains=keyword) | Q(content__contains=keyword)
    )

    # 3. 创建一个分页器
    try:
        p = Paginator(page_all, int(page_size))
    except (ValueError, TypeError):
        p = Paginator(page_all, 2)

    # 4. 利用分页器得到特定页的数据
    try:
        page_list = p.page(int(page_num))
    except (PageNotAnInteger, ValueError):
        page_list = p.page(1)
    except EmptyPage:
        page_list = p.page(p.num_pages)

    # 5. 利用特定页的数据进行文章列表和分页区域的渲染
    return render(request, 'list.html', context={
        'page_list': page_list,
        'keyword': keyword
    })


# 添加文章
def page_add(request):
    if request.method == 'GET':
        form = PostForm()
    else:
        form = PostForm(request.POST)
        if form.is_valid():
            form.save()
            messages.add_message(request, messages.SUCCESS, '添加文章成功')
            return redirect('/blog/list/')
    return render(request, 'add.html', context={
        'form': form,
    })


from django.shortcuts import render, get_object_or_404, redirect
from django.contrib import messages
from .forms import PostForm
from .models import Article, Profile


# 编辑文章，
def page_edit(request, id):
    article = get_object_or_404(Article, id=id)

    if request.method == 'GET':
        form = PostForm(instance=article)
    else:
        form = PostForm(request.POST, instance=article)
        if form.is_valid():
            form.save()
            messages.add_message(request, messages.SUCCESS, '编辑文章成功')
            return redirect('/blog/list/')  # 使用命名 URL 进行重定向

    return render(request, 'edit.html', context={
        'form': form,
    })


# 删除文章
def page_delete(request, id):
    article = get_object_or_404(Article, id=id)
    article.delete()
    messages.add_message(request, messages.SUCCESS, '删除文章成功')
    return redirect('/blog/list/')


# 用户注册登录""


# 注册页面
def register(request):
    if request.method == 'POST':
        form = UserCreationForm(data=request.POST)
        if form.is_valid():
            user = form.save()
            Profile.objects.create(user=user)  # 创建对应的 Profile 对象
            return redirect('login')
    else:
        form = UserCreationForm()
    return render(request, 'register.html', {'form': form})


# 登录页面
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.forms import AuthenticationForm
from django.shortcuts import render, redirect


def login_view(request):
    if request.method == 'POST':
        form = AuthenticationForm(request, data=request.POST)
        if form.is_valid():
            username = form.cleaned_data.get('username')
            password = form.cleaned_data.get('password')
            user = authenticate(request, username=username, password=password)
            if user is not None:
                login(request, user)
                return redirect('index')  # 登录成功后重定向到个人管理页面
            else:
                form.add_error(None, '无效的用户名或密码')
    else:
        form = AuthenticationForm()
    return render(request, 'login.html', {'form': form})


# 用户修改
@login_required
def profile(request):
    user = request.user
    try:
        profile = user.profile
    except Profile.DoesNotExist:
        profile = Profile.objects.create(user=user)
    if request.method == 'POST':
        user_form = UserForm(request.POST, instance=user)
        profile_form = ProfileForm(request.POST, request.FILES, instance=profile)
        if user_form.is_valid() and profile_form.is_valid():
            user_form.save()
            profile_form.save()
            return redirect('profile')
    else:
        user_form = UserForm(instance=user)
        profile_form = ProfileForm(instance=profile)
    return render(request, 'profile.html', {'user_form': user_form, 'profile_form': profile_form})


# 注销登录
def logout_view(request):
    logout(request)
    return redirect('login')

# render 和 redirect 用于渲染模板和重定向请求。
# PasswordResetForm 是Django提供的用于处理密码重置请求的表单。
# default_token_generator 用于生成密码重置令牌。
# urlsafe_base64_encode 和 force_bytes 用于生成和编码用户ID。
# send_mail 用于发送邮件。
# User 是Django内置的用户模型。
# settings 用于访问项目设置。
# reverse 用于生成URL
def password_reset_request(request):
    if request.method == 'POST':
        form = PasswordResetForm(request.POST)
        if form.is_valid():
            email = form.cleaned_data['email']

            associated_users = User.objects.filter(email=email)
            if associated_users.exists():
                for user in associated_users:
                    uid = urlsafe_base64_encode(force_bytes(user.pk))
                    token = default_token_generator.make_token(user)
                    reset_url = reverse('password_reset_confirm', kwargs={'uidb64': uid, 'token': token})
                    send_mail(
                        '重置您的密码',
                        f'请点击以下链接重置您的密码: {request.build_absolute_uri(reset_url)}',
                        settings.EMAIL_HOST_USER,
                        [email],
                        fail_silently=False,
                    )
                    print(f"邮件已发送到: {email}")
            return redirect('password_reset_done')
    else:
        form = PasswordResetForm()
    return render(request, 'password_reset_request.html', {'form': form})

def password_reset_confirm(request, uidb64, token):
    try:
        uid = force_str(urlsafe_base64_decode(uidb64))
        user = User.objects.get(pk=uid)
    except (TypeError, ValueError, OverflowError, User.DoesNotExist):
        user = None

    if user is not None and default_token_generator.check_token(user, token):
        if request.method == 'POST':
            form = SetPasswordForm(user, request.POST)
            if form.is_valid():
                form.save()
                return redirect('password_reset_complete')
        else:
            form = SetPasswordForm(user)
        return render(request, 'password_reset_confirm.html', {'form': form})
    else:
        return render(request, 'password_reset_invalid.html')